<template>
    <div class="upload-wrap" v-loading="loading" loading-tip="文件正在上传，请耐心等待...">
        <a-upload-dragger name="file" :multiple="multiple" :showUploadList="false" :customRequest="handleUpdoadingFile" :beforeUpload="handleBeforeUpload">
            <flexbox justify="center" align="center">
                <p class="ant-upload-drag-icon"><InboxOutlined /></p>
                <span>添加文档或<a style="text-decoration: underline">浏览</a></span>
            </flexbox>
            <p class="ant-upload-text">{{ placeholder || '支持：.rar .zip .doc .docx .pdf .jpg...' }}</p>
        </a-upload-dragger>
        <slot name="extra" />
        <div class="file-list-cont">
            <assets-file v-bind="$attrs" :fileList="showFileList" @download="handleDownFile" @remove="remove" @preview="handlePreviewFile" />
        </div>
    </div>
</template>

<script lang="ts">
import { getFileTypeWithExt } from '@/utils/file/file';
import AssetsFile from '@/components/AssetsFile/AssetsFile.vue';
import { message } from 'ant-design-vue';
import { deepClone } from '@/utils/util';
import { genPercentAdd, fileToObject, getFileItem } from '@/utils/uploadFile';
import { InboxOutlined } from '@ant-design/icons-vue';
import api from '@/api';
import { useDownFile } from '@/hooks/common/useFile';
import { computed, defineComponent, ref, unref, watch, reactive, toRefs } from 'vue';
import store from '@/store';
import uuid from 'node-uuid';
export default defineComponent({
    props: {
        fileList: {
            type: Array,
            default: () => []
        },
        multiple: {
            type: Boolean,
            default: true
        },
        fileParams: {
            type: Object,
            default: () => ({})
        },
        detail: {
            type: Object,
            default: () => ({})
        },
        placeholder: {
            type: String,
            default: '支持：.rar .zip .doc .docx .pdf .jpg...'
        }
    },
    emits: ['valueChange'],
    components: {
        InboxOutlined,
        AssetsFile
    },
    setup(props, { emit }) {
        const { downFile, previewFile } = useDownFile();
        const allFileList = ref<any>([]); // 已经存在的文件(详情返回)
        const state = reactive<any>({
            loading: false
        });
        const totalFile = ref<number>(0);
        //筛选出没有删除的文件
        const showFileList = computed(() => {
            return allFileList.value.filter((file: any) => file.status !== 'delete');
        });
        const handleUpdoadingFile = (options: any) => {
            state.loading = true;
            totalFile.value++; // 文件数量加1
            const name = options.file.name.replace(/[?？*<>()（）{}$&:："“”|\\/\\[\]【】]/gi, '');
            const file: any = new File([options.file], name);
            file.uid = options.file.uid;
            // let file = options.file;
            // console.log(file);
            const chunkSize = 1024 * 1024 * 100; // 每个切片100M大小
            const formData = new FormData();
            formData.append('files', file);
            console.log(props.fileParams);
            if (props.fileParams && props.fileParams.connectType === '更新包') {
                formData.append('systemName', props.fileParams.systemName);
                formData.append('suffix', props.fileParams.versionNumber);
            }
            // 更新进度条数值
            const autoUpdateProgress = (percent: number, file: any) => {
                const targetItem = getFileItem(file, unref(allFileList));
                if (!targetItem) {
                    return;
                }
                targetItem.percent = percent * 100;
            };
            const config = {
                // 增加进度条事件，上传中会不断调用该方法
                onUploadProgress: (progressEvent: any) => {
                    const percent = genPercentAdd()(progressEvent.loaded / progressEvent.total);
                    let targetItem = fileToObject(file);
                    // 当前上传文件
                    targetItem.status = 'uploading';
                    targetItem = {
                        ...targetItem,
                        ...props.fileParams
                    };
                    const fileIndex = unref(allFileList).findIndex(({ uid }) => uid === targetItem.uid);
                    // console.log(unref(allFileList), fileIndex);
                    if (fileIndex === -1) {
                        allFileList.value.push(targetItem);
                    } else {
                        allFileList.value[fileIndex] = targetItem; // 保证是同一文件覆盖
                    }
                    autoUpdateProgress(percent, targetItem);
                },
                cancelDuplicated: true //取消重复检测
            };
            //如果文件大小小于切片最小单位
            if (file.size <= chunkSize) {
                api.fileModel
                    .upload(formData, config)
                    .then((res) => {
                        // 可能会出现超时
                        if (res.success && res.moule) {
                            message.success(`${file.name}上传成功`);
                            options.onSuccess(res, options.file); //这个会添加response信息字段
                            const { fileName, url, urlWps } = res.moule[0];
                            const item = {
                                fileName,
                                url,
                                urlWps,
                                status: 'add',
                                userName: store.getters.userInfo.employeeDTO.name,
                                uploadUser: store.getters.userInfo.employeeDTO.empId,
                                ...props.fileParams
                            };
                            console.log(unref(allFileList), options.file, totalFile);
                            const index = unref(allFileList).findIndex((item) => item.uid === options.file.uid);
                            if (index >= 0) {
                                allFileList.value[index] = { ...item };
                            }
                            // 避免重复保存
                            const total = unref(allFileList).filter((item) => item.status === 'add').length;
                            //批量
                            if (totalFile.value > 1) {
                                if (total === totalFile.value) {
                                    totalFile.value = 0;
                                    state.loading = false;
                                    emit('valueChange', deepClone(unref(allFileList)));
                                }
                            }
                            // 一张一张传
                            else {
                                totalFile.value = 0;
                                state.loading = false;
                                emit('valueChange', deepClone(unref(allFileList)));
                            }
                        } else {
                            // 手动添加status，不然超时情况无法捕捉
                            const targetItem = getFileItem(file, unref(allFileList));
                            if (targetItem) {
                                targetItem.status = 'error';
                            }
                            message.error(`${file.name}上传失败`);
                        }
                    })
                    .catch(() => {
                        options.onError(); //这个会添加response和error信息字段，status会从uploading变为error
                        message.error(`${file.name}上传失败`);
                    });
            } else {
                uploadAssets(file, chunkSize, options);
            }
        };
        // 上传切片
        // 以chunkSize分割成fileChunkList数组，循环遍历请求接口，记录返回的总数据量和文件总数量相比，相等即位全部传完
        const uploadAssets = (file, chunkSize, options) => {
            const chunkNumber: any = Math.ceil(file.size / chunkSize); // 切片数量
            let cur = 0;
            const fileChunkList: any = [];
            let index = 1;
            let newUuid = uuid.v4().replace(/-/g, '');

            // 更新包特殊处理uuid
            if (props.fileParams && props.fileParams.connectType === '更新包') {
                newUuid = props.fileParams.systemName + '.' + props.fileParams.versionNumber;
            }

            // 创建文件
            const targetItem = {
                uid: options.file.uid,
                fileName: file.name,
                status: 'uploading',
                percent: 0,
                ...props.fileParams
            };
            allFileList.value.push(targetItem);
            while (cur < file.size) {
                const data: any = {};
                data.fileSize = file.size;
                data.uuid = newUuid;
                data.hash = file.name + '-' + index;
                data.chunk = index;
                data.size = chunkSize;
                data.chunkTotal = chunkNumber;
                data.fileName = file.name;
                data.file = file.slice(cur, cur + chunkSize);
                fileChunkList.push(data);
                cur += chunkSize;
                index += 1;
            }
            let hasError = false;
            let requestIndex = 0;
            for (let i = 0, len = fileChunkList.length; i < len; i++) {
                if (hasError) {
                    console.log(1111);
                    break;
                }
                const data = fileChunkList[i];
                const formData = new FormData();

                formData.append('fileName', data.fileName);
                formData.append('fileSize', data.fileSize);
                formData.append('size', data.size);
                formData.append('uuid', data.uuid);
                formData.append('file', data.file);
                formData.append('hash', data.hash);
                formData.append('chunkTotal', data.chunkTotal);
                formData.append('chunk', data.chunk);
                // await api.acmdbModel.uploadFile(formData);
                api.fileModel.multipartUpload(formData).then((res) => {
                    const { moule, success, errorMsg } = res;
                    if (success) {
                        if (moule) {
                            // message.success(`${file.name}上传成功`);
                            options.onSuccess(res, options.file); //这个会添加response信息字段
                            const { fileName, url } = moule;
                            const item = {
                                fileName,
                                url,
                                status: 'add',
                                userName: store.getters.userInfo.employeeDTO.name,
                                uploadUser: store.getters.userInfo.employeeDTO.empId,
                                ...props.fileParams
                            };
                            const index = unref(allFileList).findIndex((item) => item.uid === options.file.uid);
                            if (index >= 0) {
                                allFileList.value[index] = { ...item };
                            }
                            // 避免重复保存
                            const total = unref(allFileList).filter((item) => item.status === 'add').length;

                            //批量
                            if (totalFile.value > 1) {
                                if (total === totalFile.value) {
                                    totalFile.value = 0;
                                    state.loading = false;
                                    emit('valueChange', deepClone(unref(allFileList)));
                                }
                            }
                            // 一张一张传
                            else {
                                totalFile.value = 0;
                                state.loading = false;
                                emit('valueChange', deepClone(unref(allFileList)));
                            }
                        } else {
                            const index = unref(allFileList).findIndex((item) => item.uid === targetItem.uid);
                            if (index >= 0) {
                                ++requestIndex;
                                allFileList.value[index] = { ...allFileList.value[index], percent: ~~((100 / len) * (requestIndex + 1)) };
                            }
                        }
                    }
                    if (!success && errorMsg) {
                        // 手动添加status，不然超时情况无法捕捉
                        const targetItem = getFileItem(file, unref(allFileList));
                        if (targetItem) {
                            targetItem.status = 'error';
                        }
                        message.error(`${file.name}上传失败`);
                        state.loading = false;
                        hasError = true;
                    }
                });
            }
        };
        // 上传前检测大小
        const handleBeforeUpload = (file): boolean => {
            const size: number = file.size;
            const max = 500;
            // 不能带有[]符号
            // if (/[?？*<>()（）{}$&:："“”|\\/\\[\]【】]/gi.test(file.name)) {
            //     message.error('上传文件名称不能带有特殊符号：?？*"“”(){}<>$&:|/\\[]【】');
            //     return false;
            // }
            // 校验文件名
            if (props.fileParams.connectType === '更新包') {
                const files = props.detail.files.filter((item) => item.connectType === props.fileParams.connectType);
                const fileName = file.name.replace(/[?？*<>()（）{}$&:："“”|\\/\\[\]【】]/gi, '');
                const type = getFileTypeWithExt(fileName);
                if (['word', 'pdf', 'excel', 'ppt'].includes(type)) {
                    message.error('暂不支持以下类型文件：word,pdf,excel,ppt');
                    return false;
                }
                const name = props.fileParams.systemName + '.' + props.fileParams.versionNumber + '-' + fileName;
                const res = files.some((item) => item.fileName === name);
                if (res) {
                    message.error('文件已存在');
                    return false;
                }
            }
            if (size / 1024 / 1024 > max) {
                message.error('上传文件过大');
                return false;
            }
            return true;
        };
        // 下载
        const handleDownFile = (item) => {
            downFile(item, !!props.detail?.pmpTestInformationDTO);
        };
        const handlePreviewFile = (item) => {
            previewFile(item, !!props.detail?.pmpTestInformationDTO);
        };
        // 删除
        const remove = (file: any) => {
            const index = unref(allFileList).findIndex((item) => (file.url ? item.url === file.url : item.urlWps === file.urlWps));
            if (index >= 0) {
                allFileList.value[index] = {
                    ...allFileList.value[index],
                    status: 'delete'
                };
            }
            emit('valueChange', deepClone(unref(allFileList)));
        };
        watch(
            () => props.fileList,
            (n) => {
                if (n) {
                    const ids = n.map((item: any) => item.id);
                    const files = allFileList.value.filter((item) => item.status === 'uploading' && !ids.includes(item.id));
                    allFileList.value = [...n, ...files];
                }
            },
            {
                immediate: true,
                deep: true
            }
        );
        return { ...toRefs(state), allFileList, showFileList, handleUpdoadingFile, handleBeforeUpload, handleDownFile, remove, handlePreviewFile };
    }
});
</script>

<style lang="less">
// 上传
.ant-upload.ant-upload-drag {
    .ant-upload-text {
        color: #8e94a1 !important;
        font-size: 12px !important;
    }
    p.ant-upload-drag-icon {
        margin-bottom: -4px !important;
        margin-right: 8px;
        .anticon {
            font-size: 18px;
            color: #000;
        }
    }
}
.file-list-cont {
    margin-top: 8px;
}
</style>